`ifndef MY_TRANSACTION_SVH
`define MY_TRANSACTION_SVH
class my_transaction extends uvm_sequence_item;
    // When transaction changed, the monitor may be affected,
    // so check the monitor when the transaction was changed.
    rand bit [47:0] dmac;
    rand bit [47:0] smac;
    rand bit [15:0] vlan_info1;
    rand bit [ 2:0] vlan_info2;
    rand bit        vlan_info3;
    rand bit [11:0] vlan_info4;
    rand bit [15:0] ether_type;
    rand byte       pload[];
    rand bit [31:0] crc;
    //rand byte       tload[];
    // When crc_err is 1, add crc error
    rand bit        crc_err;
    rand bit        is_vlan;
    //rand byte       is_vlan;

    constraint pload_cons{
        pload.size >= 46;
        pload.size <= 1500;
    }

    //constraint tload_cons{ tload.size inside {[1:2]};}

    // introduce UVM field_automation, 
    `uvm_object_utils_begin(my_transaction)
        `uvm_field_int(dmac, UVM_ALL_ON)
        `uvm_field_int(smac, UVM_ALL_ON)
        // if-else in uvm_object_utils_begin
        // UVM-1.2 support?
        //if(is_vlan)begin
        //    `uvm_field_int(vlan_info1, UVM_ALL_ON)
        //    `uvm_field_int(vlan_info2, UVM_ALL_ON)
        //    `uvm_field_int(vlan_info3, UVM_ALL_ON)
        //    `uvm_field_int(vlan_info4, UVM_ALL_ON)
        //end
        `uvm_field_int(vlan_info1, UVM_ALL_ON)
        `uvm_field_int(vlan_info2, UVM_ALL_ON)
        `uvm_field_int(vlan_info3, UVM_ALL_ON)
        `uvm_field_int(vlan_info4, UVM_ALL_ON)
        `uvm_field_int(ether_type, UVM_ALL_ON)
        `uvm_field_array_int(pload, UVM_ALL_ON)
        `uvm_field_int(crc, UVM_ALL_ON)
        //`uvm_field_int(is_vlan, UVM_ALL_ON)
        `uvm_field_int(is_vlan, UVM_ALL_ON | UVM_NOPACK)
        //`uvm_field_array_int(tload, UVM_ALL_ON)
        // UVM_NOPACK will NOT pack crc_err;
        `uvm_field_int(crc_err, UVM_ALL_ON | UVM_NOPACK)
    `uvm_object_utils_end

    function bit[31:0] calc_crc();
        return 32'h0;
    endfunction

    function void post_randomize();
        `uvm_info(this.get_type_name(), "post_randomize", UVM_LOW)
        if(crc_err)
            crc = 32'hFFFF_FFFF;
        else
            crc = calc_crc();
    endfunction

//    `uvm_object_utils(my_transaction)
    
    function new(string name = "my_transaction");
        super.new(name);
    endfunction

    extern function void my_print();
    extern function void my_copy(my_transaction tr);
    extern function bit my_compare(my_transaction tr);
endclass

function void my_transaction::my_print();
    $display("dmac = %0h", dmac);
    $display("smac = %0h", smac);
    $display("ether_type = %0h", ether_type);
    for(int i = 0; i < pload.size(); i++)begin
        $display("pload[%0d] = %0h", i, pload[i]);
    end
    $display("crc = %0h", crc);
endfunction

function void my_transaction::my_copy(my_transaction tr);
    if(tr == null)
        `uvm_fatal("my_transaction", "tr is null")
    dmac = tr.dmac;
    smac = tr.smac;
    ether_type = tr.ether_type;
    pload = new[tr.pload.size()];
    for(int i = 0; i < pload.size(); i++)begin
        pload[i] = tr.pload[i];
    end
    crc = tr.crc;
endfunction

function bit my_transaction::my_compare(my_transaction tr);
    bit result;
    if(tr == null)
        `uvm_fatal("my_transaction", "tr is null")
    result = (dmac == tr.dmac) &&
             (smac == tr.smac) &&
             (ether_type == tr.ether_type) &&
             (crc == tr.crc);
    if(pload.size() != tr.pload.size())begin
        result = 0;
    end else begin
        for(int i = 0; i < pload.size(); i++)begin
            if(pload[i] != tr.pload[i])
                result = 0;
        end
    end
    return result;
endfunction
`endif
